package com.plumecache.core.interceptor;

import com.plumecache.core.CacheService;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class CacheInterceptorChain {
    private List<CacheInterceptor> interceptors;

    public List<CacheInterceptor> getInterceptors() {
        return this.interceptors;
    }

    public void setInterceptors(List<CacheInterceptor> interceptors) {
        if (null != interceptors) {
            interceptors = interceptors.stream().sorted((r1, r2) -> Integer.compare(r2.getOrder(), r1.getOrder())).collect(Collectors.toList());
        }

        this.interceptors = interceptors;
    }

    boolean applyPreHandle(CacheService target, Method method, Object[] args, Map<String, Object> context) {
        if (null == interceptors) {
            return true;
        }

        for (CacheInterceptor interceptor : interceptors) {
            if (!interceptor.preHandle(target, method, args, context)) {
                this.triggerAfterCompletion(target, method, args, context, null);
                return false;
            }
        }

        return true;
    }

    void applyPostHandle(CacheService target, Method method, Object[] args, Map<String, Object> context, Object result) {
        if (null == interceptors) {
            return;
        }

        for (int i = interceptors.size() - 1; i >= 0; i--) {
            CacheInterceptor interceptor = interceptors.get(i);
            interceptor.postHandle(target, method, args, context, result);
        }
    }

    void triggerAfterCompletion(CacheService target, Method method, Object[] args, Map<String, Object> context, Exception ex) {
        if (null == interceptors) {
            return;
        }

        for (int i = interceptors.size() - 1; i >= 0; i--) {
            try {
                CacheInterceptor interceptor = interceptors.get(i);
                interceptor.afterCompletion(target, method, args, context, ex);
            } catch (Throwable throwable) {
                log.error("CacheInterceptor.afterCompletion threw exception", throwable);
            }
        }
    }
}
